#! /usr/local/bin/python
"""
punch: a script to punch in/out to record work time.

Usage: punch <action>
punch in
punch out
punch cancel
punch restart
punch status
punch history
punch archive
"""

import os
import shutil
import sys
import time
from optparse import OptionParser

def parse_line(input):
  return input.strip().split(',')

def load_file(filename):
  data = []
  in_file = open(filename)
  try:
    for line in in_file:
      data.append(parse_line(line))
    return data
  finally:
    in_file.close()

def write_file(filename, data):
  file = open(filename, 'w')
  try:
    for record in data:
      file.write(','.join(record) + '\n')
  finally:
    file.close()

def append_record(filename, data):
  data_file =  open(filename, 'a')
  try:
    data_file.write(data + '\n')
  finally:
    data_file.close()

def punch_out(data_filename, notes=''):
  data = load_file(data_filename)
  if data and data[-1][0]=="in":
    new_record = ','.join(['out', str(time.time()), notes])
    append_record(data_filename, new_record)
    elapsed = (( time.time() - float(data[-1][1])) / 60.0)
    print "Punched out. The last session lasted %d minutes." % elapsed
  else:
    raise ValueError('You are not punched in')

def punch_in(data_filename, notes=''):
  data = load_file(data_filename)
  if not data or data[-1][0] == "out":
    new_record = ','.join(['in', str(time.time()), notes])
    append_record(data_filename, new_record)
    print "Punched in."
  else:
    raise ValueError('You are not punched out.')

def print_row(row):
  newrow = list(row)
  newrow[1] = time.strftime('%a,%Y-%m-%d %H:%M:%S',time.localtime(int(float(newrow[1]))))
  print '\t'.join(newrow)

def print_history(data, num_lines=1000):
  "num_lines zeroed means displaying all lines"
  if not data:
    print "No data."
    return
  start_index = -1 * num_lines
  #for row in  data[start_index:]:
  for i in xrange(len(data)):
    print_row(data[i])
    if data[i][0] == "out" and data[i-1][0] == "in":
      print "Session elapsed: %d minutes." % ( int( float(data[i][1]) - float(data[i-1][1])) / 60.0)

def print_status(data):
  if data:
    last_row = data[-1]
    last_action = last_row[0]
    if last_action == "out":
      print "Punched out."
    elif last_action == "in":
      print "Punched in for %d minutes" % ((time.time() - float(data[-1][1]))/ 60.0)
  else:
    print "data file is empty."

def cancel_latest_punch_in(data_filename):
  data = load_file(data_filename)
  if data and data[-1][0] == "in":
    data = data[:len(data)-1]
  else:
    print "You are not punched in."
  write_file(data_filename, data)

def archive_data(data_filename, archive_filename):
  print "archiving data file from %s to %s" % (data_filename, archive_filename)
  if data_filename and archive_filename:
    shutil.copyfile(data_filename, archive_filename)
  else:
    raise ValueError("data and archive filenames must both be supplied. Hint: -a for archive filename")


def run(options, args):
  if len(args) == 0:
    print_status(load_file(options.data_file))
  else:
    action = args[0]
    if action in ('in', 'i'):
      punch_in(options.data_file, ' '.join(args[1:])) 
    elif action in ('o', 'out'):
      punch_out(options.data_file, ' '.join(args[1:])) 
    elif action in ('h', 'history'):
      print_history(load_file(options.data_file), options.display_count)
    elif action in ('s', 'status'):
      print_status(load_file(options.data_file))
    elif action in ('c', 'cancel'):
      cancel_latest_punch_in(options.data_file)
    elif action in ('a', 'archive'):
      archive_data(options.data_file, options.archive_filename)
    else:
      print "unknown command: %s" % action


if __name__ == "__main__":
  option_parser = OptionParser()
  option_parser.add_option('-v','--verbose', dest='verbose', default=True, help='Verbose mode.')
  option_parser.add_option('-f','--data-file', dest='data_file', default= os.getenv('HOME') + '/punch/data')
  option_parser.add_option('-a','--archive-file', dest='archive_filename', default = None)
  option_parser.add_option('-c','--display-count', dest='display_count', default=1000, type="int", help='Number of latest records to display')
  option_parser.add_option('-n','--notes', dest='notes', default='', help='Additional notes about this item')
  options, args = option_parser.parse_args()
  run(options, args)
